local filename = "noderequest.lua"

local skynet = require "skynet"
local cluster = require "skynet.cluster"
require "skynet.manager"

local servicepoolmng = require "incrservicepoolmng"
local configdao = require "configdao"
local timetool = require "timetool"
local filelog = require "filelog"
local tabletool = require "tabletool"

require "mjexenum"

local CMD = {}
local service = nil
local base_rid = 1111111

function CMD.init(caller)
	service = caller -- 这里的caller，是router
    service.wait_entertable = { }   --等待进桌队列,防止多次进桌
end

function CMD.request(msg,...)
    local f = CMD[msg]
    if not f then
        return { retcode = EErrCode.ERR_INVALID_REQUEST,retstr = "消息不存在！"}
    end

    return f(...)
end

--------------------------------------

--
-- 生成一个桌子号，随机码
-- 这里暂时是本节点生成，以后要去 hall 生成,带入的两个参数，也是准备传到 hallnode 的
--
local function gen_table_code(table_index, create_rid, table_conf)
	-- local node 生成

	-- 去hall节点生成code，同时 hall节点保存了code -> index 对应关系
	-- hall节点也可以是gata节点
	local status,newcode = skynet.pcall(cluster.call,"hallnode", ".router", "create_table_code",skynet.getenv("nodename"), table_index, create_rid, table_conf)
    if not status then return end
	return newcode
end

--
--加入练习桌
--
local function join_practice_table(table_index,table_service,need_robot)
    local roledatas = { }
    local status = false
    local seat_indexs = { }

    --skynet.sleep(300)

    --进桌
    for i = 1,need_robot  do
        base_rid = base_rid + 1
        roledatas[i] = {
            info = { 
                rolename = "陪练" .. i, --名字
                level = 0,              --等级
		        logo = "2",             --头像
		        sex = 2,                --性别
                rid = base_rid,
            },
            money = {
                diamond = 100000,
                fangka = 1000,
                coin = 100000,
                dou = 100000,
                lock_diamond = 0,
             },
             is_robot = true,
        }
        skynet.pcall(skynet.call,table_service, "lua", "entertable", roledatas[i].info.rid, roledatas[i])
    end

    --坐下
    for i = 1,need_robot  do
        status,msg = skynet.pcall(skynet.call,table_service, "lua", "sitdowntable", roledatas[i].info.rid, roledatas[i],{ })
        seat_indexs[i] = msg.seat_index
    end

    --准备
    for i = 1,need_robot  do
        skynet.pcall(skynet.call,table_service, "lua", "gameready", roledatas[i].info.rid, roledatas[i],{ table_index = table_index })
        skynet.send(table_service,"lua","cmd","init_robot",seat_indexs[i])
    end
end

-------------------

--
-- 初始化table池
--
function CMD.init_table_pool(nodeconf)
	service.idle_table_mng = servicepoolmng:new({}, {service_name="table", service_size=nodeconf.tablesize, incr=nodeconf.tableinrc})
end

--
-- 这里收到的就就是协议的 createtable，命令，所以不能修改
--
function CMD.createtable(rid, roledata, msgbody)
    --设置停服标记后，不能创建桌子
    if service.gameend_flag then
        return {retcode = EErrCode.ERR_INVALID_REQUEST, retstr = "服务器维护中"}
    end

    --进桌中，不能建桌
    if service.wait_entertable[rid] or service.role_map[rid] then
        return 
    end

    --自建房卡,检查房卡数量
    local table_conf = msgbody.table_conf
    local playermoney = roledata.money or { }
	if table_conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_FANGKA then
        local need_num = 0
        if table_conf.retain_to_num == 4 then
            need_num = 200
        elseif table_conf.retain_to_num == 8 then
            need_num = 400
        end
		if table_conf.card_cost_type ~= nil and table_conf.card_cost_type ~= 1 then
            need_num = math.floor(need_num / table_conf.max_player_num)
        end

        local coin = playermoney.coin
		if not coin or coin < need_num then
            local response = { }
			response.retcode = EErrCode.ERR_NOT_ENOUGH_ROOMCARD
			response.retstr = "金币数量不够！"
			return	response
		end

        if not table_conf.max_player_num 
        or not table_conf.retain_to_num then
            local response = { }
		    response.retcode = EErrCode.ERR_INVALID_PARAMS
		    response.retstr = "创建房间参数错误！"
		    return	response
        end
    end 

	--判断钻石场
    if table_conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI 
    or table_conf.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
        local response = { }
        table_conf.leave_diamond = table_conf.leave_diamond or 0
        if not table_conf.score_diamond or table_conf.score_diamond <= 0 then
            response.retcode = EErrCode.ERR_INVALID_PARAMS
		    response.retstr = "底注不能为空或负！"
		    return	response
        end
        if not table_conf.enter_diamond or table_conf.enter_diamond <= 0 then
            response.retcode = EErrCode.ERR_INVALID_PARAMS
		    response.retstr = "余额不能为空或负！"
		    return	response
        end
        if table_conf.enter_diamond < table_conf.score_diamond then
            response.retcode = EErrCode.ERR_INVALID_PARAMS
		    response.retstr = "底注不能大于进桌携带量！"
		    return	response
        end

        local diamond = playermoney.diamond or 0
        if table_conf.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
            diamond = diamond + (playermoney.coin or 0)
            if not playermoney.coin or playermoney.coin < 10 then
                diamond = 0
            end
        end
        if diamond <= table_conf.leave_diamond 
        or diamond < table_conf.enter_diamond then
            response.retcode = EErrCode.ERR_NOT_ENOUGH_DIAMOND
		    response.retstr = "您的余额不足，不能创建房间！"
            if table_conf.table_type == EMJTableType.TABLE_TYPE_JIN_BI_CHANG then
                response.retstr = "您的余额不足，不能创建房间！"
            end
		    return	response
        end
    end

    local table_service = service.idle_table_mng:create_service()
	if table_service == nil then
		filelog.sys_error("create_table roomsvr's idle_table_mng not enough table_service!")
		return {retcode = EErrCode.ERR_SYSTEM_ERROR,retstr = "system error!"}
	end

	-- msgbody 里面包含了创建房间的配置， 具体在 proto 里的 tablecfg 里面定义
	-- 先生成一个table_service, 然后生成 code， 然后生成对应关系，
	-- 然后把 msgbody里的conf 传入进去 然后再去初始化这个table_service
	local table_index = service.table_index
	local table_code = gen_table_code(service.table_index, rid, msgbody.table_conf)
    if not table_code then
        skynet.call(table_service.service, "lua", "cmd", "kill_service")
        return	{retcode = EErrCode.ERR_SYSTEM_ERROR,retstr = "系统错误！"}
    end
   
	service.index_to_table[table_index] = {table_service = table_service.service,
													code = table_code}
	service.code_to_index[table_code] = table_index
	service.table_index = service.table_index + 1

    local tradeid = service:get_tradeid()
	local attachconf = {index = table_index, 
						code = table_code,
						rid = rid,
						rolename = roledata.info.rolename,
                        logo = roledata.info.logo,
                        table_service =table_service.service,
                        agencylevel = roledata.info.agencylevel,
                        tradeid = tradeid,
                        table_persist = roledata.table_persist,  --桌子没人保留时间
                        is_matchtable = msgbody.is_matchtable,   --是否是匹配桌
                        match_type    = msgbody.match_type,      --匹配桌类型
                       }
	-- 如果失败，回滚刚才的操作（不过这个失败可能性很小，因为这个操作，只是对一些对象赋值
    service.wait_entertable[rid] = true
	local result = skynet.call(table_service.service, "lua", "start", msgbody.table_conf, attachconf)
    filelog.sys_info("table_code:",table_code,"table_index:",table_index,table_service.service)
    service.wait_entertable[rid] = nil

	return {table_index = table_index,table_code = table_code,nodename = skynet.getenv("nodename")}
end

--
-- 进入桌子操作的时候，用户还不在某张桌子上，所以不能在table service处理，所以还需要在router里面处理
-- 这里做了个兼容，可以使用 table_index , 也可以使用table_code ，如果有 table_index 则先用index直接进入
-- 如果没有index，只有 table_code ,则用table_code 找到对应的index ,再进入。
--
function CMD.entertable(rid, roledata, msgbody)
    --设置停服标记后，不能进入桌子
    if service.gameend_flag then
        return {retcode = EErrCode.ERR_INVALID_REQUEST, retstr = "服务器维护中"}
    end

    --进桌中
    if service.wait_entertable[rid] or service.role_map[rid] then
        return 
    end

	local table_index 
	if msgbody.table_index then
		table_index = msgbody.table_index
	elseif msgbody.table_code and service.code_to_index[msgbody.table_code] then
		table_index = service.code_to_index[msgbody.table_code]
	else
		return {retcode = EErrCode.ERR_INVALID_TABLE_INDEX, retstr="无效桌号"}
	end

    --通过entertable，不能进入练习桌
    if service.practice_table.full_table[table_index]
    or service.practice_table.idle_table[table_index] then
        return {retcode = EErrCode.ERR_INVALID_TABLE_INDEX, retstr="房间不存在"}
    end

    --通过entertable，不能进入匹配桌
    if service.CMD.check_is_matchtable(table_index) then
        return {retcode = EErrCode.ERR_INVALID_TABLE_INDEX, retstr="房间不存在"}
    end

    --通过entertable，不能进入金币场
    if service.CMD.coinmatch("check_is_matchtable",table_index) then
        return {retcode = EErrCode.ERR_INVALID_TABLE_INDEX, retstr="房间不存在"}
    end

	local table_service
	if service.index_to_table[table_index] then 
		table_service = service.index_to_table[table_index].table_service
	else
        --通知gate，玩家离桌
        service:unforward(rid, table_index,roledata.money.diamond)
		return {retcode = EErrCode.ERR_INVALID_TABLE_INDEX, retstr="房间不存在"}
	end

    service.wait_entertable[rid] = true
	local status,result = skynet.pcall(skynet.call,table_service, "lua", "entertable", rid, roledata)
    service.wait_entertable[rid] = nil

	-- 如果成功,只有正确结构返回，没有 retcode，所以要通知gate去更改状态。
	if result and result.retcode == nil then
		service:forward(rid, table_service, table_index,roledata.money.diamond)
	end

	return result
end

--
-- 获取公开桌列表
--
function CMD.getpubtablelist(rid, roledata)
	local tablelist = {publist={},mylist={},matchlist = {}}
    local tableobj = nil
    local ret_num = 200  --返回条数
    local j = 1

    --获得公开桌
    local status = false
	for _,item in pairs(service.index_to_table) do
        status,tableobj = skynet.pcall(skynet.call,item.table_service,"lua","cmd","get_table_data")
        if status and tableobj and tableobj.conf then
            if tableobj.conf.table_type == EMJTableType.TABLE_TYPE_ZIJIAN_ZUANSHI then
                if tableobj.conf.is_public == 1 then
                    tablelist.publist[j] = {
				        table_index	= tableobj.table_index,
		                table_code	= tableobj.table_code,
		                dizhu 		= tableobj.conf.score_diamond,      --底注
		                ruchang		= tableobj.conf.enter_diamond,      --入场
		                lichang		= tableobj.conf.leave_diamond,      --离场
		                conf_intro	= tabletool.deepcopy(tableobj.conf),
		                max_player	= tableobj.conf.max_player_num,
		                cur_player	= tableobj.cur_player,
		                create_time	= tableobj.create_time,
		            }
                    j = j + 1
                    if j > ret_num then
                        break
                    end
                end
            end
        end
	end

    --获得匹配场信息
    tablelist.matchlist = service.CMD.get_matchlist()

	return tablelist
end

--
--玩家断开连接
--
function CMD.disconnect(rid, roledata)
    filelog.print("----------------Disconnect----",rid)

    --在匹配队列，将其踢出
    service.CMD.cancelmatch(rid, roledata)
    service.CMD.coinmatch("cancelmatch", rid, roledata)

    return true
end

--
--断线重连
--
function CMD.reentertable(rid, roledata,request)
    local notciemsg = { }
    notciemsg.retcode = EErrCode.ERR_INVALID_REQUEST
    notciemsg.retstr = "不在桌子内！"
    service:unforward(rid, request.table_index,roledata.money.diamond)
    return notciemsg
end

--
--进入练习桌
--
function CMD.entertraintable(rid, roledata, request)
    --设置停服标记后，不能进入桌子
    if service.gameend_flag then
        return {retcode = EErrCode.ERR_INVALID_REQUEST, retstr = "服务器维护中"}
    end

    --进桌中
    if service.wait_entertable[rid] or service.role_map[rid] then
        return 
    end

    local table_index = 0
    for k,v in pairs(service.practice_table.idle_table) do
        table_index = k
        break
    end

    if table_index == 0 then
        service.CMD.create_some_practice_table(1)
        for k,v in pairs(service.practice_table.idle_table) do
            table_index = k
            break
        end
        if table_index == 0 then 
            return {retcode = EErrCode.ERR_INVALID_REQUEST,retstr = "没有空的练习桌"} 
        end
    end
    
    table_service = service.index_to_table[table_index].table_service
    service.wait_entertable[rid] = true
    local status,result = skynet.pcall(skynet.call,table_service, "lua", "entertable", rid, roledata)
    service.wait_entertable[rid] = nil
	if result and result.retcode == nil then
        service:forward(rid, table_service, table_index,roledata.money.diamond)
        --加入机器人
        local need_robot = 3 - (result.table_gameinfo.table_baseinfo.sitdown_player_num or 0)
        skynet.fork(join_practice_table,table_index,table_service,need_robot)
        service.practice_table.full_table[table_index] = table_index
        service.practice_table.idle_table[table_index] = nil
    end

	return result
end

return CMD